Skip to main content

NextAuth

This guide describes how to configure NextAuth.js to support authentication via OAuth2 and manage access tokens originating from gov.gr endpoints. It includes code examples and practical tips for secure integration.

Setting Up NextAuth for OAuth2 Token Management

This file contains a custom configuration of NextAuth.js using the credentials provider. It securely manages access/refresh tokens, extends JWTs, and organizes sessions for an OAuth2 flow.

Overview

The configuration:

  • Uses CredentialsProvider to manage custom tokens (access and refresh).
  • Extends the User, Token, and Session types in NextAuth with custom fields.
  • Stores tokens in the JWT and handles their expiration.
  • Optionally configures cookies (commented out).

Full Code with Explanations

Imports

import { addSeconds, getUnixTime } from "date-fns";
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
  • addSeconds and getUnixTime help compute expiration times.
  • NextAuth is the main authentication function.
  • CredentialsProvider handles the custom login.

Type Extensions

declare module "next-auth" {
interface QueryParams {
access_token: string;
refresh_token: string;
role: string;
name: string;
afm: string;
}

interface User extends QueryParams {
id?: string;
}

interface Token extends QueryParams {
exp: number;
}

interface Session {
user: QueryParams;
}
}

Adds afm, role, name, and tokens to the NextAuth types.

Credentials Provider Setup

providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
access_token: { label: "Access Token", type: "text" },
refresh_token: { label: "Refresh Token", type: "text" },
role: { label: "Role", type: "text" },
first_name: { label: "First Name", type: "text" },
last_name: { label: "Last Name", type: "text" },
afm: { label: "AFM", type: "text" },
},
async authorize(credentials) {
if (!credentials?.access_token) {
console.error("No access token provided");
return null;
}
return {
access_token: credentials.access_token,
refresh_token: credentials.refresh_token,
role: credentials.role,
name: `${credentials.first_name} ${credentials.last_name}`,
afm: credentials.afm,
};
},
}),
],
  • Defines fields for user input.
  • Returns a complete user object for the JWT.

Session & Pages Configuration

pages: {
signIn: "/",
},
session: {
strategy: "jwt",
maxAge: 60 * 60, // 1 hour
},
secret: process.env.NEXTAUTH_SECRET,
  • Redirects to / for login.
  • Uses JWT without database-backed sessions.
  • Session lifetime is 1 hour.

JWT Callback

callbacks: {
async jwt({ token, user }) {
const now = getUnixTime(new Date());

if (user) {
token.access_token = user.access_token;
token.refresh_token = user.refresh_token;
token.role = user.role;
token.name = user.name;
token.afm = user.afm;
token.exp = getUnixTime(addSeconds(new Date(), 60 * 60)); // 1 hour
}

if (typeof token.exp === "number" && now > token.exp) {
delete token.access_token;
delete token.refresh_token;
delete token.role;
delete token.name;
delete token.afm;
delete token.exp;
}

return token;
},
  • Stores data in the token after login.
  • Checks for expiration and removes sensitive fields.

Session Callback

 async session({ session, token }) {
const now = getUnixTime(new Date());

if (typeof token.exp === "number" && now > token.exp) {
return { ...session, user: { ...session.user } }; // Έληξε το session
} else {
session.user = {
access_token: token.access_token as string,
refresh_token: token.refresh_token as string,
role: token.role as string,
name: token.name as string,
afm: token.afm as string,
};
}

return session;
},
},
  • Copies the token into the session.
  • Does not return expired sessions.

Usage Example

After logging in through the OAuth2Login page, the provider:

  • Receives the token and user info
  • Creates a JWT
  • Populates the session with all necessary fields

Summary

This configuration enables secure login based on custom tokens with NextAuth in a Next.js application.

  • Securely stores tokens
  • Manages expiration
  • Supports custom fields like AFM, role, and name

We'd love your feedback
Was this helpful?